package com.ihr360.cnb.module.payroll.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ihr360.authority.embed.base.annotation.CheckStaffIdList;
import com.ihr360.authority.embed.base.entity.AuthStaffDataModel;
import com.ihr360.authority.embed.base.entity.AuthStaffDataRequest;
import com.ihr360.authority.embed.base.type.AuthorityStaffStatus;
import com.ihr360.cnb.module.common.service.Ihr360StaffApiService;
import com.ihr360.cnb.module.insurance.service.MemberPlanAggregateService;
import com.ihr360.cnb.module.insurance.service.feign.InsuranceService;
import com.ihr360.cnb.module.oneclick.service.IrenshiDubboProviderService;
import com.ihr360.cnb.module.payroll.job.AttendanceSyncJob;
import com.ihr360.cnb.module.payroll.service.IrenshiAttendanceDubboProviderService;
import com.ihr360.cnb.module.payroll.service.PayrollAggregateService;
import com.ihr360.cnb.module.payroll.service.PayrollService;
import com.ihr360.commons.context.session.Ihr360SessionContextHolder;
import com.ihr360.commons.entity.AuthUserInfo;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.DateUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.model.meta.table.DynamicCell;
import com.ihr360.commons.model.type.ProgressType;
import com.ihr360.commons.vo.ResultInfo;
import com.ihr360.entity.ApplicationApprovalEntity;
import com.ihr360.entity.BasicStaffCurrentSalaryInfo;
import com.ihr360.entity.BasicStaffInfoEntity;
import com.ihr360.entity.IrsStaffSalaryProfile;
import com.ihr360.entity.PageData;
import com.ihr360.entity.StaffBankSalaryEntity;
import com.ihr360.entity.SyncedRosterSalaryChangeRecordEntity;
import com.ihr360.excel.ExcelUtil;
import com.ihr360.excel.cellstyle.ExcelCellStyle;
import com.ihr360.excel.cellstyle.ExcelCellStyleFactory;
import com.ihr360.excel.entity.ExportParams;
import com.ihr360.insurance.entity.vo.BenefitCompanySettingEntity;
import com.ihr360.maven.plugin.ModuleCodeStore;
import com.ihr360.payroll.config.system.SystemSalaryFieldEntity;
import com.ihr360.payroll.entity.setting.SalaryCompanySettingEntity;
import com.ihr360.payroll.entity.staff.CompanySalaryProfileEntity;
import com.ihr360.payroll.entity.staff.SalaryProfileEntity;
import com.ihr360.payroll.entity.staff.SalaryProfileFieldEntity;
import com.ihr360.payroll.entity.staff.SalaryProfileItemsWrapperEntity;
import com.ihr360.payroll.entity.staff.StaffPayrollInfoJournalEntity;
import com.ihr360.payroll.entity.staff.StaffSalaryEntity;
import com.ihr360.payroll.entity.staff.StaffSalaryProfileEntity;
import com.ihr360.payroll.request.ApplicationApprovalRequest;
import com.ihr360.payroll.request.SalaryProfileFieldRequest;
import com.ihr360.payroll.request.SalaryProfileTypeItem;
import com.ihr360.payroll.request.StaffPayrollInfoJournalRequest;
import com.ihr360.payroll.request.StaffPayrollInfoRequest;
import com.ihr360.payroll.request.StaffPayrollInfosRequest;
import com.ihr360.payroll.request.StaffSalaryProfileSearchBody;
import com.ihr360.payroll.request.attendance.AttendanceOverTimeRequest;
import com.ihr360.payroll.request.attendance.AttendanceTakeNumberRequest;
import com.ihr360.payroll.response.StaffPayrollInfoResponse;
import com.ihr360.payroll.response.attendance.AttendanceSummaryResponse;
import com.ihr360.payroll.type.AttendanceState;
import com.ihr360.payroll.type.SalaryProfileChangeType;
import com.ihr360.sharedservice.api.DataCacheService;
import com.ihr360.type.StaffStatus;
import com.ihr360.validation.ValidationUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.servlet.ServletOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author richey
 */
@Service
public class PayrollAggregateServiceImpl implements PayrollAggregateService {

    private static final Logger logger = LoggerFactory.getLogger(PayrollAggregateServiceImpl.class);

    private static final String BASIC_SALARY_CODE = "basesalary";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_NAME = "name";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_MOBILE = "mobileNo";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_DEPARTMENT = "department";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_ENROLLINDATE = "enrollInDate";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_EFFECTIVEAT = "effectiveAt";
    public static final String STAFF_SALARY_IMPORT_HEADER_KEY_ADJUST_RESSON = "adjustReason";

    @Autowired
    private IrenshiDubboProviderService irenshiDubboProviderService;

    @Autowired
    private PayrollService payrollService;

    @Autowired
    private DataCacheService dataCacheService;

    @Autowired
    private AttendanceSyncJob attendanceSyncJob;

    @Autowired
    private InsuranceService insuranceService;

    @Autowired
    private MemberPlanAggregateService memberPlanAggregateService;

    @Autowired
    private Ihr360StaffApiService ihr360StaffApiService;

    @Autowired
    private IrenshiAttendanceDubboProviderService irenshiAttendanceDubboProviderService;

    /**
     * 初始化1：公司薪资档案批量初始化
     *
     * @return
     */
    @Override
    public ResultInfo batchInitCompanySalaryProfile() {
        ResultInfo resultInfo = payrollService.batchInitCompanySalaryProfile();
        return resultInfo;
    }

    /**
     * 初始化2：需要同步的数据
     *
     * @return
     */
    @Override
    public Boolean initIrsProbationData() {

        logger.info("－－－－－－－－－－开始进行员工转正数据迁移");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("查找irs需要迁移转正数据的公司");
        List<String> companyIds = irenshiDubboProviderService.getIrsSalaryProbationCompanyIds();
        stopWatch.stop();
        if (companyIds == null) {
            logger.error("未查到需要迁移转正员工数据的公司");
            return true;
        }
        logger.info("－－－－－－－－－－需要迁移转正的公司有{}家，公司Id:{}", companyIds.size(), JSONObject.toJSONString(companyIds));

        stopWatch.start("迁移所有公司的员工薪资转正数据");
        int i = 0;
        for (String companyId : companyIds) {

            List<IrsStaffSalaryProfile> irsStaffSalaryProfiles = irenshiDubboProviderService.getIrsSalaryProfile(companyId);
            if (CollectionUtils.isEmpty(irsStaffSalaryProfiles)) {
                continue;
            }
            List<String> exitStaffIds = payrollService.probationReviewStaffIdsFromIrs(companyId);


            StaffPayrollInfoRequest salaryProfile = new StaffPayrollInfoRequest();
            irsStaffSalaryProfiles = irsStaffSalaryProfiles.stream()
                    .filter(s -> s.getNewValueEffectiveAt() != null
                            && (CollectionUtils.isEmpty(exitStaffIds) || !exitStaffIds.contains(s.getStaffId())))
                    .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(irsStaffSalaryProfiles)) {
                continue;
            }

            for (IrsStaffSalaryProfile irsStaffSalaryProfile : irsStaffSalaryProfiles) {
                List<SalaryProfileTypeItem> typeItems = Lists.newArrayList();
                salaryProfile.setStaffId(irsStaffSalaryProfile.getStaffId());
                salaryProfile.setCompanyId(irsStaffSalaryProfile.getCompanyId());
                SalaryProfileTypeItem oldItem = getSalaryProfileTypeItem(irsStaffSalaryProfile, true);
                SalaryProfileTypeItem item = getSalaryProfileTypeItem(irsStaffSalaryProfile, false);
                typeItems.add(oldItem);
                typeItems.add(item);
                salaryProfile.setTypeItems(typeItems);
                ResultInfo resultInfo = payrollService.abnormalityAdjustProfile(salaryProfile);
                if (resultInfo.isErrorResult()) {
                    logger.error(resultInfo.getMessage());
                } else {
                    logger.info(resultInfo.getMessage());
                }
                i++;
            }

        }
        stopWatch.stop();
        logger.info(String.format("－－－－－－－－－－数据迁移结束,总共迁移员工%s人", i));
        logger.info(stopWatch.prettyPrint());
        logger.info(String.valueOf(stopWatch.getTotalTimeMillis()));
        return true;
    }

    /**
     * 初始化3：初始化除员工转正数据之外的其他员工数据
     *
     * @return
     */
    @Override
    public ResultInfo initExcludeFromIrs() {
        //所有公司
        List<String> allCompanyIds = payrollService.getAllCompanyIds();
        Date currentDate = new Date();
        SystemSalaryFieldEntity basesalary = payrollService.getBasicSalaryField(BASIC_SALARY_CODE);
        int count = 0;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("所有公司员工薪资数据迁移");
        List<StaffSalaryProfileEntity> toSave = Lists.newArrayListWithCapacity(10000);
        List<StaffPayrollInfoJournalEntity> journalToSave = Lists.newArrayList();
        for (String companyId : allCompanyIds) {

            //todo 测试本公司
            if (!"b5c1d3a9-0c01-4f04-beaf-802e5d696038".equals(companyId)) {
                continue;
            }

            List<String> exitStaffIds = payrollService.findStaffIdsForExistSalaryProfile(companyId);
            List<BasicStaffCurrentSalaryInfo> staffInfos = irenshiDubboProviderService.findStaffSalaryInfoExceptStaffids(companyId, exitStaffIds);
            CompanySalaryProfileEntity companySalaryProfile = payrollService.findCompanySalaryProfileId(companyId);


            if (CollectionUtils.isEmpty(staffInfos)) {
                continue;
            }
            for (BasicStaffCurrentSalaryInfo staffInfo : staffInfos) {
                StaffSalaryProfileEntity staffSalaryProfile = new StaffSalaryProfileEntity();
                staffSalaryProfile.setCompanyId(companyId);
                BasicStaffInfoEntity staffInfoEntity = new BasicStaffInfoEntity();
                staffInfoEntity.setId(staffInfo.getId());
                staffSalaryProfile.setStaff(staffInfoEntity);

                SalaryProfileEntity salaryProfile = new SalaryProfileEntity();
                staffSalaryProfile.setSalaryProfile(salaryProfile);

                salaryProfile.setCompanySalaryProfile(companySalaryProfile);
                salaryProfile.setChangeType(SalaryProfileChangeType.INIT);

                SalaryProfileItemsWrapperEntity wrapper = new SalaryProfileItemsWrapperEntity();
                Map<String, DynamicCell> items = Maps.newHashMap();
                DynamicCell dynamicCell = new DynamicCell();
                dynamicCell.setCellValue(String.valueOf(staffInfo.getCurrentSalary()));
                items.put(basesalary.getCode(), dynamicCell);
                wrapper.setItems(items);
                salaryProfile.setWrapper(wrapper);
                salaryProfile.setEffectiveAt(currentDate);
                staffSalaryProfile.setSalaryProfile(salaryProfile);
                toSave.add(staffSalaryProfile);

                StaffPayrollInfoJournalEntity journal = new StaffPayrollInfoJournalEntity();
                journal.setStaffId(staffInfo.getId());
                journal.setReason("初始化员工薪资档案数据");
                journal.setChangeType(SalaryProfileChangeType.INIT);
                journal.setCreatedAt(currentDate);
                journal.setFieldName(basesalary.getName());
                journal.setFieldCode(basesalary.getCode());
                journal.setNewValue(String.valueOf(staffInfo.getCurrentSalary()));
                journal.setCompanyId(companyId);
                journalToSave.add(journal);
                journal.setEffectiveAt(currentDate);
                count++;

                if (toSave.size() % 10000 == 0) {
                    payrollService.saveStaffSalaryProfiles(toSave);
                    payrollService.saveStaffSalaryProfileJournals(journalToSave);
                    toSave = Lists.newArrayListWithCapacity(10000);
                }

            }
        }
        if (toSave.size() % 10000 != 0) {
            payrollService.saveStaffSalaryProfiles(toSave);
            payrollService.saveStaffSalaryProfileJournals(journalToSave);
        }

        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());
        logger.info(String.valueOf(stopWatch.getTotalTimeMillis()));
        logger.info("-----------end---初始化除irs数据迁移之外的员工薪资档案数据结束,共初始化数据" + count + "条");

        return new ResultInfo.Builder().success();
    }

    @Override
    public void takeNumber(AuthUserInfo userInfo, AttendanceTakeNumberRequest request) {
        request.setUserInfo(userInfo);
        AttendanceSummaryResponse summaryResponse = payrollService.attendanceTakeNumber(request);
        if (summaryResponse == null || summaryResponse.getSummaryId() == null) {
            throw new Ihr360Exception(null, "考勤汇总记录保存失败");
        }
        Long summaryId = summaryResponse.getSummaryId();
        dataCacheService.put(ProgressType.ATTENDANCE_SUMMARY.name() + summaryId, "0");
        request.setSummaryId(summaryId);
        attendanceSyncJob.takeNumberMonthlyReport(request);
    }

    @Override
    public Map<String, Integer> getUnapprovedCount(String companyId, AttendanceTakeNumberRequest request) {
        return irenshiDubboProviderService.getUnapprovedCount(companyId, request);
    }

    @Override
    @CheckStaffIdList
    public void saveStaffSalaryInfo(List<String> staffIds, StaffSalaryEntity staffSalaryEntity) {
        payrollService.saveStaffSalaryInfo(staffSalaryEntity);
        staffSalaryEntity.setTaxRole(null);
        staffSalaryEntity.setWorkHourType(null);
        staffSalaryEntity.setCompanySalaryProfileEntity(null);
        staffSalaryEntity.setStaffSalary(null);
        irenshiDubboProviderService.saveStaffSalaryInfo(staffSalaryEntity);
    }

    @Override
    public ResultInfo adjustStaffSalaryProfile(SyncedRosterSalaryChangeRecordEntity entity) {

        //组织数据保存
        String staffId = entity.getStaffId();
        String companyId = entity.getCompanyId();
        if (StringUtils.isEmpty(staffId) || StringUtils.isEmpty(companyId)) {
            throw new Ihr360Exception(null, "薪资调整失败，公司id:" + companyId + ",员工id:" + staffId);
        }
        String staffName = irenshiDubboProviderService.getStaffName(staffId);

        Date effectiveAt = entity.getChangeDate();
        if (effectiveAt == null) {
            throw new Ihr360Exception(null, "薪资调整失败，生效时间不能为空！");
        }
        String changeContent = entity.getChangeContent();
        if (StringUtils.isEmpty(changeContent)) {
            throw new Ihr360Exception(null, "薪资调整失败，调整内容不能为空！");
        }
        Double changeValue = getChangeValue(changeContent);
        String effectiveAtStr = DateUtils.formatDateStr(effectiveAt, DateUtils.STANDARD_DATE_FORMAT_YM1);
        SalaryProfileChangeType changeType = getSalaryChangeType(entity.getChangeReason());
        List<StaffSalaryProfileEntity> staffSalaryProfiles = payrollService.getStaffSalaryProfiles(staffId, companyId);
        if (staffSalaryProfiles == null) {
            staffSalaryProfiles = Lists.newArrayList();
        }
        CompanySalaryProfileEntity companySalaryProfile = payrollService.findCompanySalaryProfileId(companyId);
        boolean haveSameType = false;

        if (CollectionUtils.isNotEmpty(staffSalaryProfiles)) {
            for (StaffSalaryProfileEntity staffSalaryProfile : staffSalaryProfiles) {
                if (isSameMonthAndType(effectiveAtStr, changeType, staffSalaryProfile)) {
                    adjustSalaryProfile(effectiveAt, changeValue, changeType, companySalaryProfile, staffSalaryProfile);
                    haveSameType = true;
                    break;
                }
            }
        }
        if (!haveSameType) {
            StaffSalaryProfileEntity staffSalaryProfile = new StaffSalaryProfileEntity();
            staffSalaryProfile.setCompanyId(companyId);
            BasicStaffInfoEntity staffInfoEntity = new BasicStaffInfoEntity();
            staffInfoEntity.setId(staffId);
            staffSalaryProfile.setStaff(staffInfoEntity);
            adjustSalaryProfile(effectiveAt, changeValue, changeType, companySalaryProfile, staffSalaryProfile);
            staffSalaryProfiles.add(staffSalaryProfile);
        }

        StaffPayrollInfoRequest request = new StaffPayrollInfoRequest();
        request.setCompanyId(companyId);
        request.setStaffId(staffId);
        request.setStaffName(staffName);
        request.setUserId(entity.getUserId());
        request.setUserName(entity.getUserName());
        List<SalaryProfileTypeItem> typeItems = Lists.newArrayList();
        request.setTypeItems(typeItems);

        for (StaffSalaryProfileEntity staffSalaryProfile : staffSalaryProfiles) {
            SalaryProfileTypeItem item = new SalaryProfileTypeItem();
            SalaryProfileEntity salaryProfileEntity = staffSalaryProfile.getSalaryProfile();
            item.setChangeType(salaryProfileEntity.getChangeType());
            item.setEffectiveAt(salaryProfileEntity.getEffectiveAt());
            List<SalaryProfileFieldRequest> profileFields = Lists.newArrayList();
            item.setProfileFields(profileFields);

            SalaryProfileItemsWrapperEntity wrapper = salaryProfileEntity.getWrapper();
            Map<String, DynamicCell> items = wrapper.getItems();
            items.forEach((code, cell) -> {
                SalaryProfileFieldRequest salaryProfileFieldRequest = new SalaryProfileFieldRequest();
                salaryProfileFieldRequest.setCode(code);
                salaryProfileFieldRequest.setChangeType(salaryProfileEntity.getChangeType());
                if (staffSalaryProfile.getId() == null) {
                    salaryProfileFieldRequest.setAdjustManually(false);
                }
                salaryProfileFieldRequest.setValue(cell.getCellValue());
                profileFields.add(salaryProfileFieldRequest);
            });
            typeItems.add(item);
        }

        StaffPayrollInfosRequest infos = new StaffPayrollInfosRequest();
        infos.setPayrollInfos(Lists.newArrayList(request));
        return payrollService.adjustSalaryProfileWrapper(infos);
    }

    @Override
    public String submitApproval(AuthUserInfo userInfo, ApplicationApprovalRequest applicationApprovalRequest) {
        String resultMessage = "";
        Long id = applicationApprovalRequest.getId();
        if (ApplicationApprovalRequest.BENEFIT_TYPE.equals(applicationApprovalRequest.getType())) {
            //查询公司福利账期设置
            BenefitCompanySettingEntity benefitSetting = insuranceService.queryBenefitCompanySetting(applicationApprovalRequest.getCompanyId());
            if (benefitSetting != null && benefitSetting.getBenefitApproval()) {//需要提请审批
                ApplicationApprovalEntity response = irenshiDubboProviderService.submitApproval(applicationApprovalRequest);
                insuranceService.saveApprovalApplicationId(applicationApprovalRequest.getCompanyId(), response, id);
                resultMessage = "提请审批成功";
            } else {//设置为无需审批，直接扭转福利账期状态
                insuranceService.closeLedgerSummary(id);
                memberPlanAggregateService.saveIncreaseMemberRecords(userInfo.getCompanyId(), userInfo.getUserId(), id);
                memberPlanAggregateService.saveDecreaseMemberRecords(userInfo.getCompanyId(), userInfo.getUserId(), id);
                resultMessage = "福利台账结果已提交，免审批通过！";
            }
        } else if (ApplicationApprovalRequest.PAYROLL_TYPE.equals(applicationApprovalRequest.getType())) {
            //查询公司薪酬账期设置
            SalaryCompanySettingEntity setting = payrollService.querySalaryCompanySetting(applicationApprovalRequest.getCompanyId());
            if (setting != null && setting.isPayPeriodApproval()) {//需要提请审批
                ApplicationApprovalEntity response = irenshiDubboProviderService.submitApproval(applicationApprovalRequest);
                payrollService.saveApprovalApplicationId(applicationApprovalRequest.getCompanyId(), response, id);
                resultMessage = "提请审批成功";
            } else {//设置为无需审批，直接扭转账期状态
                payrollService.closeActivePeriod(applicationApprovalRequest.getCompanyId(), id);
                resultMessage = "薪资核算结果已提交，免审批通过！";
            }
        } else {
            throw new Ihr360Exception(null, "不支持该类型审批");
        }
        return resultMessage;
    }

    @Override
    public void lockAttendanceState(AuthUserInfo userInfo, Long summaryId, AttendanceState state) {
        //修改考勤汇总状态
        AttendanceOverTimeRequest request = payrollService.lockAttendanceState(summaryId, state);
        AttendanceState oldState = request.getState();
        //调用考勤接口回写加班数据
        if (request != null && !request.getIsImport() && CollectionUtils.isNotEmpty(request.getStaffOverTimeRequestList())) {
            request.setCompanyId(userInfo.getCompanyId());
            request.setOperatorId(userInfo.getUserId());
            request.setOperatorName(userInfo.getMobileNo());
            try {
                request.setState(state);
                irenshiAttendanceDubboProviderService.syncOvertimeData(request);
            } catch (Exception e) {
                //回滚薪资方案状态
                payrollService.rollBackState(summaryId, oldState);
                throw new Ihr360Exception(null, e.getCause().getMessage());
            }
        }
    }

    @Override
    public void initStaffBankInfo() {
        logger.info("－－－－－－－－－－开始进行员工银行卡、纳税身份数据迁移");
        String lastId = "";
        Boolean isOver = false;
        int limitSize = 500;
        int isFix = 0;
        while (!isOver) {
            logger.info("已修复公司数量:" + isFix);
            List<String> companyIdList = irenshiDubboProviderService.getAllCompanyIds(lastId, limitSize);
            //如果查询出的公司列表为空或者小于limit大小，认为已查询完不继续查询公司循环
            if (CollectionUtils.isEmpty(companyIdList) || companyIdList.size() < limitSize) {
                isOver = true;
            }
            int size = companyIdList.size();
            isFix = isFix + size;
            lastId = companyIdList.get(size - 1);
            logger.info("--需要同步的公司数量:" + size);
            int i = 0;
            for (String companyId : companyIdList) {
                i++;
                logger.info("--当前同步的公司数量:" + i + "/" + size);
                logger.info("--当前同步的公司id:" + companyId);
                List<StaffBankSalaryEntity> staffBankSalaryEntityList = irenshiDubboProviderService.getCompanyStaffInfo(companyId);
                if (CollectionUtils.isEmpty(staffBankSalaryEntityList)) {
                    logger.info("--员工信息为空，继续下一个公司");
                    continue;
                }
                logger.info("--需要同步的员工数量" + staffBankSalaryEntityList.size());
                //保存员工银行卡信息
                try {
                    payrollService.saveAllStaffSalaryInfo(companyId, staffBankSalaryEntityList);
                } catch (Exception e) {
                    logger.info("--同步员工银行卡异常");
                    logger.error(e.getMessage(), e);
                }
                //保存福利信息
                try {
                    insuranceService.saveAllInsurance(companyId, staffBankSalaryEntityList);
                } catch (Exception e) {
                    logger.info("--同步福利信息异常");
                    logger.error(e.getMessage(), e);
                }
            }
        }
        logger.info("－－－－－－－－－－结束员工银行卡、纳税身份数据迁移");
    }

    @Override
    public StaffPayrollInfoResponse getCurrentEffectiveStaffSalarys(StaffSalaryProfileSearchBody param, boolean noPaged) {
        StaffPayrollInfoResponse response = new StaffPayrollInfoResponse();
        AuthStaffDataRequest request = new AuthStaffDataRequest();
        request.setPage(param.getPage());
        request.setRows(param.getSize());
        String authCode = ModuleCodeStore.Module.SALARY_CODE;
        request.setAuthorityCode(authCode);
        if (CollectionUtils.isNotEmpty(param.getDepartmentIds())) {
            request.setDepartIdList(param.getDepartmentIds());
        }
        if (param.getStaffStatus() != null) {
            if (StaffStatus.IN_SERVICE == param.getStaffStatus()) {
                request.setAuthorityStaffStatus(AuthorityStaffStatus.IN_SERVICE);
            } else if (StaffStatus.QUIT == param.getStaffStatus()) {
                request.setAuthorityStaffStatus(AuthorityStaffStatus.QUIT);
            }
        }
//        request.setAuthorityStaffStatus(AuthorityStaffStatus.IN_SERVICE);
        request.setStaffName(param.getStaffName());
        PageData<AuthStaffDataModel> staffAuthDatas = null;
        if (noPaged) {
            List<AuthStaffDataModel> allAuthStaffs = ihr360StaffApiService.getAllAuthStaffs(request);
            if (allAuthStaffs == null) {
                allAuthStaffs = Lists.newArrayList();
            }
            staffAuthDatas = new PageData<>(1, allAuthStaffs.size(), allAuthStaffs);
        } else {
            staffAuthDatas = ihr360StaffApiService.getAuthStaffs(request);
        }

        if (staffAuthDatas == null || CollectionUtils.isEmpty(staffAuthDatas.getContent())) {
            response.setPageDate(new com.ihr360.commons.vo.PageData<>(0, 0, Lists.newArrayList()));
            return response;
        }

        List<AuthStaffDataModel> authStaffDatas = staffAuthDatas.getContent();

        List<String> authStaffIds = authStaffDatas.stream().map(AuthStaffDataModel::getStaffId).collect(Collectors.toList());

        StaffSalaryProfileSearchBody searchBody = new StaffSalaryProfileSearchBody();
        searchBody.setTotalElements(staffAuthDatas.getTotalElements());
        searchBody.setTotalPages(staffAuthDatas.getTotalPages());
        BeanUtils.copyProperties(param, searchBody);
        searchBody.setAuthStaffIds(authStaffIds);
        searchBody.setTotalPages(staffAuthDatas.getTotalPages());
        searchBody.setTotalElements(staffAuthDatas.getTotalElements());

        return payrollService.getCurrentEffective(searchBody);
    }

    @Override
    @CheckStaffIdList()
    public ResultInfo adjustSalaryProfileWrapper(List<String> staffIdList, StaffPayrollInfosRequest staffpayrollInfos) {
        return payrollService.adjustSalaryProfileWrapper(staffpayrollInfos);
    }

    @Override
    public void exportCurrent(StaffSalaryProfileSearchBody param, ServletOutputStream outputStream) {
        param.setShowCornerInfo(false);

        StaffPayrollInfoResponse response = getCurrentEffectiveStaffSalarys(param, true);
        List<StaffSalaryProfileEntity> staffSalaryProfileEntities = response.getPageDate().getContent();

        ValidationUtils.rejectIfEmpty(staffSalaryProfileEntities, null, "导出数据为空！");

        ExportParams exportParams = new ExportParams();

        //表头
        Map<String, String> headerMap = new LinkedHashMap<>();
        exportParams.setHeaderMap(headerMap);
        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_NAME, "姓名");
        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_MOBILE, "手机号");
        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_DEPARTMENT, "部门");
        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_ENROLLINDATE, "入职日期");

        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_EFFECTIVEAT, "生效日期");
        headerMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_ADJUST_RESSON, "调整原因");

        //样式
        ExcelCellStyle requiredStyle = ExcelCellStyleFactory.createRequiredHeaderCellStyle();
        Map<String, ExcelCellStyle> headerStyleMap = new HashedMap();
        headerStyleMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_NAME, requiredStyle);
        headerStyleMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_EFFECTIVEAT, requiredStyle);
        headerStyleMap.put(STAFF_SALARY_IMPORT_HEADER_KEY_ADJUST_RESSON, requiredStyle);
        exportParams.setHeaderStyleMap(headerStyleMap);

        CompanySalaryProfileEntity companySalaryProfile = payrollService.findCompanySalaryProfileId(Ihr360SessionContextHolder.getCompanyId());
        List<SalaryProfileFieldEntity> companyProfileFields = Lists.newArrayList();
        if (companySalaryProfile != null) {
            companyProfileFields = companySalaryProfile.getProfileFields();
        }


        if (CollectionUtils.isNotEmpty(companyProfileFields)) {
            companyProfileFields.forEach(salaryProfileField -> {
                headerMap.put(salaryProfileField.getCode(), salaryProfileField.getName());
            });
        }

        List<List<Object>> datas = new ArrayList<>();
        for (StaffSalaryProfileEntity staffSalaryProfileEntity : staffSalaryProfileEntities) {
            BasicStaffInfoEntity staff = staffSalaryProfileEntity.getStaff();
            SalaryProfileEntity salaryProfile = staffSalaryProfileEntity.getSalaryProfile();
            List<Object> data = new ArrayList<>();
            data.add(staff.getStaffName());
            data.add(staff.getMobileNo());
            data.add(staff.getDepartmentName());
            data.add(staff.getEnrollInDate());
            if (salaryProfile == null) {
                datas.add(data);
                continue;
            }

            data.add(salaryProfile.getEffectiveAt());
            data.add(salaryProfile.getChangeType().getTitle());
            SalaryProfileItemsWrapperEntity wrapperEntity = salaryProfile.getWrapper();
            if (wrapperEntity == null || MapUtils.isEmpty(wrapperEntity.getItems())) {
                datas.add(data);
                continue;
            }
            Map<String, DynamicCell> items = wrapperEntity.getItems();
            if (MapUtils.isNotEmpty(items)) {
                companyProfileFields.forEach(companyProfileField -> {
                    DynamicCell cell = items.get(companyProfileField.getCode());
                    if (cell != null) {
                        data.add(cell.getCellValue());
                    } else {
                        data.add(null);
                    }
                });
            }
            datas.add(data);
        }
        exportParams.setRowDatas(datas);

        ExcelUtil.exportExcel(exportParams, outputStream);
    }

    @Override
    public com.ihr360.commons.vo.PageData<StaffPayrollInfoJournalEntity> findAllJournals(StaffPayrollInfoJournalRequest param) {
        AuthStaffDataRequest request = new AuthStaffDataRequest();
        String authCode = ModuleCodeStore.Module.SALARY_CODE;
        request.setAuthorityCode(authCode);

        List<AuthStaffDataModel> allAuthStaffs = ihr360StaffApiService.getAllAuthStaffs(request);
        if (allAuthStaffs == null) {
            allAuthStaffs = Lists.newArrayList();
        }
        Set<String> authStaffIds = allAuthStaffs.stream().map(AuthStaffDataModel::getStaffId).collect(Collectors.toSet());
        param.setAuthStaffIds(Lists.newArrayList(authStaffIds));
        return payrollService.findAllAuthJournals(param);
    }

    private void adjustSalaryProfile(Date effectiveAt, Double changeValue, SalaryProfileChangeType changeType, CompanySalaryProfileEntity companySalaryProfile, StaffSalaryProfileEntity staffSalaryProfile) {
        SalaryProfileEntity salaryProfileEntity = staffSalaryProfile.getSalaryProfile();
        if (salaryProfileEntity == null) {
            salaryProfileEntity = new SalaryProfileEntity();
            salaryProfileEntity.setEffectiveAt(effectiveAt);
            salaryProfileEntity.setChangeType(changeType);
            salaryProfileEntity.setCompanySalaryProfile(companySalaryProfile);
            staffSalaryProfile.setSalaryProfile(salaryProfileEntity);
        }
        SalaryProfileItemsWrapperEntity wrapper = salaryProfileEntity.getWrapper();
        if (wrapper == null) {
            wrapper = new SalaryProfileItemsWrapperEntity();
            salaryProfileEntity.setWrapper(wrapper);
        }
        Map<String, DynamicCell> items = wrapper.getItems();
        if (items == null) {
            items = new HashMap<>();
            wrapper.setItems(items);
        }
        items.put(BASIC_SALARY_CODE, new DynamicCell(changeValue));
    }

    private SalaryProfileTypeItem getSalaryProfileTypeItem(IrsStaffSalaryProfile irsStaffSalaryProfile, boolean isOld) {
        SalaryProfileTypeItem item = new SalaryProfileTypeItem();
        item.setChangeType(SalaryProfileChangeType.PROBATION_REVIEW);
        List<SalaryProfileFieldRequest> profileFields = Lists.newArrayList();
        SalaryProfileFieldRequest salaryProfileFieldRequest = new SalaryProfileFieldRequest();
        salaryProfileFieldRequest.setName("基本工资");
        salaryProfileFieldRequest.setCode(BASIC_SALARY_CODE);
        salaryProfileFieldRequest.setChangeType(SalaryProfileChangeType.PROBATION_REVIEW);
        if (isOld) {
            salaryProfileFieldRequest.setChangeType(SalaryProfileChangeType.INIT);
            item.setChangeType(SalaryProfileChangeType.INIT);
        }

        if (isOld) {
            Calendar cal = Calendar.getInstance();
            cal.set(1970, 0, 01);
            Date oldEffectiveAt = irsStaffSalaryProfile.getOldValueEffectiveAt() == null ? cal.getTime() : DateUtils.subDays(irsStaffSalaryProfile.getOldValueEffectiveAt(), 31);
            item.setEffectiveAt(oldEffectiveAt);
            salaryProfileFieldRequest.setEffectiveAt(DateUtils.subDays(irsStaffSalaryProfile.getOldValueEffectiveAt(), 31));
            salaryProfileFieldRequest.setValue(String.valueOf(irsStaffSalaryProfile.getOldValue()));
        } else {
            item.setEffectiveAt(DateUtils.addDays(irsStaffSalaryProfile.getNewValueEffectiveAt(), 1));
            salaryProfileFieldRequest.setEffectiveAt(DateUtils.addDays(irsStaffSalaryProfile.getNewValueEffectiveAt(), 1));
            salaryProfileFieldRequest.setValue(String.valueOf(irsStaffSalaryProfile.getNewValue()));
        }

        profileFields.add(salaryProfileFieldRequest);
        item.setProfileFields(profileFields);
        return item;
    }

    private SalaryProfileChangeType getSalaryChangeType(String changeReason) {
        if (StringUtils.isEmpty(changeReason)) {
            throw new Ihr360Exception(null, "薪资调整原因不能为空！");
        }

        switch (changeReason) {
            case "试用期转正":
                return SalaryProfileChangeType.PROBATION_REVIEW;
            case "调岗调薪":
                return SalaryProfileChangeType.POSITION_OR_SALARY_ADJUSTMENT;
            default:
                throw new Ihr360Exception(null, "薪资调整原因不能为空！");
        }
    }

    private boolean isSameMonthAndType(String effectiveAtStr, SalaryProfileChangeType changeType, StaffSalaryProfileEntity s) {
        return s.getSalaryProfile() != null && s.getSalaryProfile().getEffectiveAt() != null
                && DateUtils.formatDateStr(s.getSalaryProfile().getEffectiveAt(), DateUtils.STANDARD_DATE_FORMAT_YM1).equals(effectiveAtStr)
                && s.getSalaryProfile().getChangeType() == changeType;
    }

    private Double getChangeValue(String changeContent) {
//        当前薪资从 无 变更到 8888.0
//        当前薪资从 无 变更到60000.0
//        String value = changeContent.replaceAll("[^(0-9\\.)]", "");
        String value = changeContent.substring(changeContent.indexOf("变更到") + 3);
        if ("无".equals(value) || StringUtils.isEmpty(value)) {
            return 0d;
        }
        return Double.valueOf(value.trim());
    }

}
